package com.techsoul.module.order.service.impl;

import com.alibaba.fastjson.JSON;
import com.ijpay.core.enums.SignType;
import com.ijpay.core.enums.TradeType;
import com.ijpay.core.kit.WxPayKit;
import com.ijpay.wxpay.WxPayApi;
import com.ijpay.wxpay.model.UnifiedOrderModel;
import com.techsoul.common.core.exception.BusinessException;
import com.techsoul.common.core.pojo.vo.UserVo;
import com.techsoul.common.core.util.ServletUtils;
import com.techsoul.common.core.util.collection.MapUtils;
import com.techsoul.common.core.util.lang.NumberUtils;
import com.techsoul.common.core.util.lang.StringUtils;
import com.techsoul.common.core.util.network.IpUtils;
import com.techsoul.common.security.service.TokenService;
import com.techsoul.module.system.config.WxpayProperties;
import com.techsoul.module.order.enmus.PayStatusEnum;
import com.techsoul.module.order.enmus.SalesOrderEventEnum;
import com.techsoul.module.order.enmus.SalesOrderStatusEnum;
import com.techsoul.module.order.pojo.param.SalesOrderSaveParam;
import com.techsoul.module.order.pojo.vo.SalesOrderVo;
import com.techsoul.module.order.service.IPayService;
import com.techsoul.module.order.service.ISalesOrderEventService;
import com.techsoul.module.order.service.ISalesOrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.util.*;

@Slf4j
@Service
@Transactional(readOnly = true)
public class PayServiceImpl implements IPayService {

    @Autowired
    private WxpayProperties wxpayProperties;

    @Autowired
    private TokenService tokenService;

    @Autowired
    private ISalesOrderService salesOrderService;

    @Autowired
    private ISalesOrderEventService salesOrderEventService;

    /**
     * 微信统一下单
     * @param orderId
     * @param request
     * @return
     */
    @Override
    @Transactional(readOnly = false)
    public Map<String, String> wxAppletPay(String orderId, HttpServletRequest request) {
        // 返回给小程序的支付参数
        Map<String, String> payParams = MapUtils.newHashMap();
        // 校验用户是否登录，需要获取openId
        UserVo user = tokenService.getLoginUser(ServletUtils.getRequest()).getUser();
        if (user == null || user.getOpenid() == null) {
            throw new BusinessException("未绑定微信");
        }
        // 校验支付配置
        if (wxpayProperties == null) {
            throw new BusinessException("未设置微信小程序支付配置");
        }
        // 校验订单信息
        SalesOrderVo salesOrder = salesOrderService.findById(orderId);
        if (salesOrder == null) {
            throw new BusinessException("订单数据异常");
        }
        if (PayStatusEnum.SUCCESS.getValue().equals(salesOrder.getPayStatus())) {
            throw new BusinessException("订单已支付");
        }
        // 封装微信统一下单参数
        String ip = IpUtils.getIpAddr(request); // 客户端IP
        if (StringUtils.isBlank(ip)) {
            ip = "127.0.0.1";
        }
        Map<String, String> params = UnifiedOrderModel
                .builder()
                .appid(wxpayProperties.getAppid())
                .mch_id(wxpayProperties.getMchid())
                .nonce_str(WxPayKit.generateStr())
                .body("小程序支付")
                .attach("http://localhost")
                .out_trade_no(orderId)
                .total_fee(Double.valueOf(salesOrder.getPayMoney() * 100).longValue() + "") // 支付金额(单位：分)
                .spbill_create_ip(ip)
                .notify_url(wxpayProperties.getPayNotifyUrl())
                .trade_type(TradeType.JSAPI.getTradeType())
                .openid(user.getOpenid())
                .build()
                .createSign(wxpayProperties.getPaySignKey(), SignType.HMACSHA256);
        log.info(params.toString());
        // 向微信服务端统一下单
        String xmlResult = WxPayApi.pushOrder(false, params);
        log.info(xmlResult);
        // 解析微信服务端返回的统一下单信息
        Map<String, String> result = WxPayKit.xmlToMap(xmlResult);
        String returnCode = result.get("return_code");
        String returnMsg = result.get("return_msg");
        if (!WxPayKit.codeIsOk(returnCode)) {
            log.error("支付失败," + returnMsg);
            throw new BusinessException("支付失败," + returnMsg);
        }
        String resultCode = result.get("result_code");
        String errCodeDes = result.get("err_code_des");
        if (!WxPayKit.codeIsOk(resultCode)) {
            log.error("支付失败," + errCodeDes);
            throw new BusinessException("支付失败," + errCodeDes);
        }
        // return_code、result_code都为SUCCESS时，才算下单成功，返回以下字段
        String prepayId = result.get("prepay_id");
        // 小程序预付订单再次签名，创建返回给小程序端的支付参数
        payParams = WxPayKit.miniAppPrepayIdCreateSign(wxpayProperties.getAppid(), prepayId, wxpayProperties.getPaySignKey(), SignType.HMACSHA256);
        String jsonStr = JSON.toJSONString(payParams);
        log.info("小程序支付的参数:" + jsonStr);
        // 更新订单信息-预付单号
        SalesOrderSaveParam salesOrderSaveParam = new SalesOrderSaveParam();
        salesOrderSaveParam.setId(salesOrder.getId())
                .setSalesOrderNo(salesOrder.getSalesOrderNo())
                .setPrepayId(prepayId) // 预付单号
                .setPrepayTime(new Date()) // 预付单号生成时间
                .setPrepayOpenid(user.getOpenid()) // 预付微信openid
                .setPayStatus(PayStatusEnum.DOING.getValue()); // 支付状态：支付中
        salesOrderService.update(salesOrderSaveParam);
        // 添加订单支付事件
        salesOrderEventService.insert(salesOrderSaveParam, SalesOrderEventEnum.SO_005_001);
        return payParams;
    }

    /**
     * 微信支付成功回调方法，小程序调用
     * @param orderId
     */
    @Override
    public void wxAppletPaySuccess(String orderId) {
        log.info(orderId + "支付成功");
        // todo 更新订单支付状态、状态
        SalesOrderVo salesOrder = salesOrderService.findById(orderId);
        SalesOrderSaveParam salesOrderSaveParam = new SalesOrderSaveParam();
        BeanUtils.copyProperties(salesOrder, salesOrderSaveParam);
        salesOrderSaveParam.setPayTime(new Date())
                .setPayStatus(PayStatusEnum.DOING.getValue()) // 支付状态：支付成功
                .setOrderStatus(SalesOrderStatusEnum.PAID.getValue()); // 订单状态：已支付
        salesOrderService.update(salesOrderSaveParam);
        // 添加订单支付事件
        salesOrderEventService.insert(salesOrderSaveParam, SalesOrderEventEnum.SO_005_002);
    }

    /**
     * 微信服务器异步通知
     */
    @Override
    @Transactional(readOnly = false)
    public String wxPayNotify(HttpServletRequest request) {
        return null;
    }

}
